cNamesInitialSize = 65536 ;131072

uglobal
  ptrLabels dd ?        ; ptr to Root items TArray structure.
  ptrNames  dd ?
  NamesCurrent dd ?
  NamesSize dd ?
endg


proc AddToNames, .ptrString
begin
        push    esi edi ebx

        mov     esi, [.ptrString]
        mov     edi, [ptrNames]
        mov     ebx, [NamesCurrent]
        mov     eax, [NamesSize]
        sub     eax, ebx
        cmp     eax, $100
        ja      .sizeok

        add     [NamesSize], $1000
        invoke  HeapReAlloc, [hHeap], 0, [ptrNames], [NamesSize]
        mov     [ptrNames], eax
        mov     edi, eax

.sizeok:
        mov     eax, ebx

.copyloop:
        mov     cl, [esi]
        inc     esi
        mov     [edi+ebx], cl
        inc     ebx
        test    cl,cl
        jnz     .copyloop

        mov     [NamesCurrent], ebx
        pop     ebx edi esi
        return
endp



proc CreateLabelsList, .ptrList, .ptrEnd
.Name      rb 256
.ptrIntLbl dd ?
begin
        pushad

        cmp     [ptrLabels], 0
        je      @f
        stdcall DestroyLabelsTree, ptrLabels
@@:
; Allocate memory for label names.
        invoke  HeapAlloc, [hHeap], 0, cNamesInitialSize
        mov     [ptrNames], eax
        mov     [NamesCurrent], 0
        mov     [NamesSize], cNamesInitialSize

        mov     esi, [.ptrEnd]
        mov     ebx, esi
        sub     ebx, [.ptrList]

        shr     ebx, 3
        jz      .finish

.loop:
        sub     esi, sizeof.THashListItem

        mov     eax, esi
        sub     eax, [.ptrEnd]
        lea     eax, [2*eax+esi]  ; eax = 2*(ptrHashListItem - ptrEnd) + ptrHashListItem

        mov     [.ptrIntLbl], eax   ; Address of internal fasm label structure during assembling stage.

        push    esi

; Copy the string
        mov     esi, [esi+THashListItem.ptrName]
        test    esi, esi
        jz      .next           ; it is anonymous label

        movzx   ecx, byte [esi-1]

        lea     edi, [.Name]

.copy:
        lodsb
        cmp     al, '?'         ; skip autogenerated by FASM macro local labels
        je      .next
        stosb
        loop    .copy

        xor     al,al
        stosb

        lea     eax, [.Name]
        stdcall AddToTree, eax, ptrLabels

        push    [.ptrIntLbl]
        pop     [eax+TLabel.ptrIntLabel]

.next:
        pop     esi
        dec     ebx
        jnz     .loop

.finish:
        popad
        return
endp


;---------------------------------------------------------------
; Returns:
;    eax - The name of the label without the first parent name.
;    edx - First parent.
;---------------------------------------------------------------
proc GetLabelParent, .ptrLabel
begin
        push    esi ebx

        mov     esi, [.ptrLabel]
        push    esi

        cmp     word [esi], '..'        ; Begins with ".."
        jne     .search

        add     esi, 2

.search:
        mov     al, [esi]
        test    al,al
        jz      .notfound
        cmp     al, '.'
        je      .found

        inc     esi
        jmp     .search

.found:
        mov     byte [esi], 0

        lea     eax, [esi+1]
        pop     edx

        pop     ebx esi
        return

.notfound:
        pop     eax
        xor     edx, edx

        pop     ebx esi
        return
endp


proc SearchCreateLabel, .ptrVarArray, .ptrLabel
.hash dd ?
begin
        push    esi edi ebx edx

        stdcall StrHash, [.ptrLabel], 0
        mov     [.hash], eax

        mov     edx, [.ptrVarArray]
        mov     esi, [edx]
        test    esi, esi
        jnz     .arrayok

        stdcall CreateArray, sizeof.TLabel
        mov     edx, [.ptrVarArray]
        mov     [edx],eax
        mov     esi, eax

        stdcall CreateArray, 8          ; Array for search tree.
        mov     [esi+TArray.lParam], eax
        lea     eax, [esi+TArray.lParam]
        stdcall AddArrayItem, eax       ; First empty element of the tree.
        mov     dword [eax], 0
        mov     dword [eax+4], 0

.arrayok:
        mov     edi, [esi+TArray.lParam]
        mov     ecx, 32         ; the depth of the tree
        mov     ebx, TArray.Items

.treeseek:
        xor     eax, eax
        ror     [.hash], 1
        adc     eax, 0
        lea     edx, [ebx+4*eax]

        mov     edx, [edi + edx]        ; eax is offset from the begining of the array.
        test    edx, edx
        jz      .notfound

        mov     ebx, edx
        loop    .treeseek

.found:                         ; the offset of the item is in the ebx register
        mov     eax, [edi+edx]
        lea     eax, [esi + eax]
        pop     edx ebx edi esi
        return


.addloop:
        xor     eax, eax
        ror     [.hash],1
        adc     eax, 0

.notfound:      ; edi - pointer to the tree array,  ebx - offset of the last found element.
                ; eax - 0 or 1 depending of the last bit checked. ecx - remaining bits count.
                ; edx = 0
        push    ecx eax

        lea     edx, [esi+TArray.lParam]
        stdcall AddArrayItem, edx
        mov     dword [eax], 0
        mov     dword [eax+4], 0

        mov     edi, edx                ; new base for the array.
        sub     eax, edx                ; offset of the new element

        xchg    eax, [esp]              ; this is the old eax
        lea     edx, [ebx+ 4*eax]

        pop     ebx
        mov     [edi+edx], ebx          ; the new offset is properly set.

        pop     ecx
        loop    .addloop

        push    eax
        mov     edx, [edi+edx]
        lea     ebx, [edi+edx]  ; address of the last element.

        stdcall AddArrayItem, [.ptrVarArray]

        mov     esi, eax
        sub     eax, edx        ; offset of the TLabel item.

        pop     ecx
        mov     [ebx+4*ecx], eax  ; stored.

        xor     eax, eax
        mov     [esi+TLabel.Children], eax
        mov     [esi+TLabel.type], al
        mov     [esi+TLabel.flags], ax
        mov     [esi+TLabel.ValueLo], eax
        mov     [esi+TLabel.ValueHi], eax
        mov     [esi+TLabel.ptrIntLabel], eax

; This should be the only place where the .hName and .hashName of TLabel is set.
        stdcall AddToNames, [.ptrLabel]
        mov     [esi+TLabel.iName], eax
        push    [.hash]
        pop     [esi+TLabel.hashName]

        mov     eax, esi
        pop     edx ebx edi esi
        return

endp

;------------------------------------------------------
; Returns: eax - pointer to new created TLabel
;          [hLabelName] content of the string will be
;          destroyed.
;------------------------------------------------------
proc AddToTree, .ptrLabelName, .ptrVarTree
begin
        push    esi edi ebx ecx

        mov     edi, [.ptrVarTree]
        mov     ebx, [.ptrLabelName]

.addloop:
        stdcall GetLabelParent, ebx
        test    edx, edx
        jz      .addhere

        mov     ebx, eax
        stdcall SearchCreateLabel, edi, edx

        lea     edi, [eax+TLabel.Children]
        jmp     .addloop

.addhere:
        stdcall SearchCreateLabel, edi, eax

        pop     ecx ebx edi esi
        return
endp




proc SearchLabel, .ptrVarArray, .hLabel
.hash dd ?
begin
        push    esi edi ebx edx

        mov     edx, [.ptrVarArray]
        mov     esi, [edx]
        test    esi, esi
        jz      .notfound

        stdcall StrHash, [.hLabel], 0
        mov     [.hash], eax

        mov     edi, [esi+TArray.lParam]
        mov     ecx, 32         ; the depth of the tree
        mov     ebx, TArray.Items

.treeseek:
        xor     eax, eax
        ror     [.hash], 1
        adc     eax, 0
        lea     edx, [ebx+4*eax]

        mov     edx, [edi + edx]        ; eax is offset from the begining of the array.
        test    edx, edx
        jz      .notfound

        mov     ebx, edx
        loop    .treeseek

.found:                         ; the offset of the item is in the ebx register
        mov     eax, [edi+edx]
        lea     eax, [esi + eax]

        pop     edx ebx edi esi
        return

.notfound:
        xor     eax, eax
        pop     edx ebx edi esi
        return
endp



proc SearchTree, .hLabelName, .ptrVarTree
begin
        push    edi ebx ecx

        mov     edi, [.ptrVarTree]
        mov     ebx, [.hLabelName]

.searchloop:
        stdcall GetLabelParent, ebx
        test    edx, edx
        jz      .here

        mov     ebx, eax
        stdcall SearchLabel, edi, edx
        test    eax, eax
        jz      .finish

        lea     edi, [eax+TLabel.Children]
        jmp     .searchloop

.here:
        mov     edx, eax
        mov     eax, edi

.finish:
        pop     ecx ebx edi
        return
endp

; returns pointer to TLabel or NULL
proc SearchTreeExact, .hLabelName, .ptrVarTree
begin
        push    edi ebx ecx

        mov     edi, [.ptrVarTree]
        mov     ebx, [.hLabelName]

.searchloop:
        stdcall GetLabelParent, ebx
        test    edx, edx
        jz      .here

        mov     ebx, eax
        stdcall SearchLabel, edi, edx
        test    eax, eax
        jz      .finish

        lea     edi, [eax+TLabel.Children]
        jmp     .searchloop

.here:
        stdcall SearchLabel, edi, eax

.finish:
        pop     ecx ebx edi
        return
endp




;proc CmpLabels, ptrLbl1, ptrLbl2
;begin
;        pushad
;
;        mov     esi, [ptrLbl1]
;        mov     edi, [ptrLbl2]
;
;        stdcall StrCmp, [esi+TLabel.hName], [edi+TLabel.hName]
;        cmp     eax, 0
;        jl      .qfalse
;
;        stc
;        popad
;        return
;
;.qfalse:
;        clc
;        popad
;        return
;endp


;*************************************
; Returns:
;   eax = 0 if the strings are equal
;   eax = 1 if str1 > str2
;   eax = -1 if str1 < str2
;*************************************
;proc StrCmp, str1, str2
;begin
;        push    esi edi ecx
;
;
;        cmp     [str1], 0
;        jne     .notfirst
;
;        cmp     [str2], 0
;        je      .zero
;        jmp     .minus
;
;
;.notfirst:
;        cmp     [str2], 0
;        je      .plus
;
;        stdcall StrPtr, [str1]
;        mov     esi, eax
;
;        stdcall StrPtr, [str2]
;        mov     edi, eax
;
;.loop:
;        mov     al, [esi]
;        lea     esi, [esi+1]
;        cmp     al, [edi]
;        lea     edi, [edi+1]
;        jg      .plus
;        jl      .minus
;
;.zero:
;        test    al,al
;        jnz     .loop
;
;        xor     eax, eax
;        jmp     .finish
;
;.plus:
;        xor     eax, eax
;        inc     eax
;        jmp     .finish
;
;.minus:
;        xor     eax, eax
;        dec     eax
;
;.finish:
;        pop     ecx edi esi
;        return
;endp
;



proc DestroyLabelsTree, .ptrVarArray
begin
        push    esi ebx

        mov     eax, [.ptrVarArray]
        mov     esi, [eax]              ; pointer to TArray
        test    esi, esi
        jz      .finish

        mov     ebx, [esi+TArray.Count]
        lea     esi, [esi+TArray.Items]

.clearlist:
        cmp     dword [esi], 0
        je      .next
        stdcall DestroyLabelsTree, esi          ; for .Children field of the TLabel
.next:
        add     esi, sizeof.TLabel
        dec     ebx
        jnz     .clearlist

        mov     eax, [.ptrVarArray]
        xchg    ebx, [eax]

        invoke  HeapFree, [hHeap], 0, [ebx+TArray.lParam]
        invoke  HeapFree, [hHeap], 0, ebx

.finish:
        cmp     [ptrNames], 0
        je      .quit

        invoke  HeapFree, [hHeap], 0, [ptrNames]
        mov     [ptrNames], 0

.quit:
        pop     ebx esi
        return
endp




proc CaptureLabelValues, .ptrVarArray

begin
        push    esi edi ebx

        mov     eax, [.ptrVarArray]
        mov     esi, [eax]              ; pointer to TArray
        test    esi, esi
        jz      .finish

        mov     ebx, [esi+TArray.Count]
        lea     esi, [esi+TArray.Items]

.iteratelist:
        cmp     dword [esi], 0
        je      .childrenok
        stdcall CaptureLabelValues, esi          ; for .Children field of the TLabel

.childrenok:
        mov     edi, [esi+TLabel.ptrIntLabel]
        test    edi, edi
        jz      .next

        mov     eax, dword [edi+TIntLabel.Value]
        mov     edx, dword [edi+TIntLabel.Value+4]
        mov     [esi+TLabel.ValueLo], eax
        mov     [esi+TLabel.ValueHi], edx

        mov     eax, dword [edi+TIntLabel.Flags]
        mov     dword [esi+TLabel.flags], eax

.next:
        add     esi, sizeof.TLabel
        dec     ebx
        jnz     .iteratelist

.finish:
        pop     ebx edi esi
        return
endp




proc ShowNotUsed
.frm TFreshMsg
begin
;        push    esi edi ebx
;
;        mov     esi, [ptrLabels]
;        test    esi, esi
;        jz      .finish
;
;        mov     ebx, [LabelsCount]
;        test    ebx, ebx
;        jz      .finish
;
;.valuesloop:
;        test    [esi+TLabel.flags], lfCanRedefine
;        jnz     .next
;
;        test    [esi+TLabel.flags], lfUsed
;        jnz     .next
;
;        cmp     [esi+TLabel.hName], 0
;        je      .next
;
;        stdcall StrNew
;        push    eax
;
;        stdcall StrCopy, eax, cHintPrefix
;        stdcall StrCat, eax, [esi+TLabel.hName]
;        stdcall StrCat, eax, cHintSuffix
;
;        mov     [.frm.type], mtInfo
;        mov     [.frm.link.hFileName], 0
;        mov     [.frm.hMessage], eax
;
;        lea     eax, [.frm]
;        invoke  SendMessage, [frmMsg], MWM_ADDMESSAGE, eax, 0
;        stdcall StrDel ; from the stack.
;
;.next:
;        add     esi, sizeof.TLabel
;        dec     ebx
;        jnz     .valuesloop
;
;.finish:
;        pop     ebx edi esi
        return
endp

iglobal
  cHintPrefix db 'The label "',0
  cHintSuffix db '" is defined but not used.',0
endg

